﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Raven.Client;
using Raven.Client.Document;
using Raven.Client.Shard;
using System.Xml.Serialization;
using System.IO;
using Raven.Client.Connection;

namespace DDBS_test
{
    public partial class Form1 : Form
    {
        Dictionary<string, IDocumentStore> shardStores;
        Shards shards;
        ShardStrategy shardStrategy;
        IDocumentStore store;


        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            InitStore();

            //WriteSamples();
            ReadSamples();

        }

        private void ReadSamples()
        {
            WriteLogLine("--------------------- ReadSamples ---------------------");
            using (IDocumentSession session = store.OpenSession())
            {
                Sample[] results;
                try
                {
                    // Get all, should automagically retrieve from each shard.
                    results = session.Query<Sample>()
                        //.Where(s => s.M0 > 0)
                        .ToArray();

                    foreach (Sample s in results)
                        WriteLogLine(s.ToString());
                }
                catch
                {
                    WriteLogLine("--offline--");
                }

            }
        }

        private void WriteSamples()
        {
            // WriteSamples.
            WriteLogLine("--------------------- WriteSamples ---------------------");
            using (IDocumentSession session = store.OpenSession())
            {
                Sample s1 = new Sample("TestSample1","JG", new List<Peak>() { new Peak(1, 1), new Peak(1, 1), new Peak(1, 1), new Peak(1, 1), new Peak(1, 1) });
                Sample s2 = new Sample("TestSample2", "JG1", new List<Peak>() { new Peak(2, 2), new Peak(2, 2), new Peak(2, 2), new Peak(2, 2), new Peak(2, 2) });
                session.Store(s1);
                session.Store(s2);
                session.SaveChanges();
                WriteLogLine(s1.ToString());
                WriteLogLine("Sample saved.");
                WriteLogLine(s2.ToString());
                WriteLogLine("Sample saved.");
            }
        }

        private void WriteLog(String text)
        {
            log.AppendText(text);
        }

        private void WriteLogLine(String text)
        {
            WriteLog(text + "\r\n");
        }

        private void InitStore()
        {
            /*
            Shard s1 = new Shard("JG", "http://localhost:8080", "DDBS");
            Shard s2 = new Shard("JG1", "http://localhost:8081", "DDBS1");
            List<Shard> shardList = new List<Shard>() { s1, s2 };
            */
            /*
            XmlSerializer serializer = new XmlSerializer(shardList.GetType());
            using ( TextWriter writer = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + @"\Shard_config.xml"))
            {
                serializer.Serialize(writer, shardList);
            }
            */

            // ReadSamples Shard config file.
            XmlSerializer deserializer = new XmlSerializer(typeof(Shards));
            TextReader reader = new StreamReader(AppDomain.CurrentDomain.BaseDirectory + @"\Shard_config.xml");
            object obj = deserializer.Deserialize(reader);
            shards = (Shards)obj;
            reader.Close();
            
            // Add shards to known stores.
            shardStores = new Dictionary<string, IDocumentStore>();
            foreach(Shard s in shards.ShardList)
            {
                shardStores.Add(s.Name, new DocumentStore { Url = s.URL, DefaultDatabase = s.DB });
            }


            // Apply sharding strategy.
            shardStrategy = new ShardStrategy(shardStores)
                .ShardingOn<Sample>(s => s.Shard);
            //shardStrategy.ShardAccessStrategy = new SequentialShardAccessStrategy(); // Sequential or parallel shard access.
            shardStrategy.ShardAccessStrategy = new ParallelShardAccessStrategy(); // Sequential or parallel shard access.

            // Setting OnError to continue when shard is unavailable. (does not work with ParallelShardAccessStrategy)
            //shardStrategy.ShardAccessStrategy.OnError += (commands, request, exception) => request.Query != null;
            shardStrategy.ShardAccessStrategy.OnError += (failingCommands, requestData, exception) =>
                {
                    if (requestData.Query == null) // query by id, cannot be handled
                        return false; // raise error

                    return true; // continue (return and continue with other shard)
                };

            // Initialize. (does not open connections)
            store = new ShardedDocumentStore(shardStrategy)
                .Initialize();
        }
    }
}
